using System;
using System.Web;
using System.Web.Routing;
using ManagedUIFlow.Infrastructure.Flows;
using ManagedUIFlow.Infrastructure.Services;
using ManagedUIFlow.Model;
using Moq;
using Xunit;

namespace ManagedUIFlow.Specs.Infrastructure.Services
{
    public class DistinctSessionFlowViewServSpecs
    {
        private readonly DistinctSessionFlowViewService _service;
        private readonly RequestContext _requestContext;
        private readonly Mock<HttpContextBase> _contextMock;
        private readonly Mock<HttpSessionStateBase> _sessionMock;
        private readonly RouteData _routeData;

        public DistinctSessionFlowViewServSpecs()
        {
            _service = new DistinctSessionFlowViewService();
            _contextMock = new Mock<HttpContextBase>();
            _routeData = new RouteData();
            _sessionMock = new Mock<HttpSessionStateBase>();
            _contextMock.Setup(c => c.Session).Returns(_sessionMock.Object);
            _requestContext = new RequestContext(_contextMock.Object, _routeData);
        }            

        [Fact]
        public void NeitherNoFlowsToDserializeNorFlowNotFoundToStart_Throws()
        {
            var flowServiceMock = new Mock<FlowService>();
            _service.FlowService = flowServiceMock.Object;

            Assert.Throws<FlowException>( () => _service.Deserialize("foo", _requestContext));
        }        

        [Fact]
        public void DserializingExistingFlow_TransitionsFlow()
        {
            var flow = new ManagedFlow("foo");
            flow.SetNavigation("bar");
            _sessionMock.Setup(s => s["foo"]).Returns(flow);
            var flowServiceMock = new Mock<FlowService>();            
            _service.FlowService = flowServiceMock.Object;

            var runningFlow = _service.Deserialize("foo", _requestContext);

            Assert.NotNull(runningFlow);
            flowServiceMock.Verify(s => s.GetNavigationFor(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
        }
             
        [Fact]
        public void SerializeFlow_PersistsinSessionState()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Manual, "");            
            _sessionMock.Setup(s => s.Add(flow.Key.ToString(), flow)).Verifiable();

            var key = _service.Serialize(flow, _requestContext);

            Assert.NotEqual(flow.Key.ToString(), key);
        }

        [Fact]
        public void PostRedirectGet_IssuesRedirect()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Auto, "");
            var responseMock = new Mock<HttpResponseBase>();
            responseMock.Setup(r => r.Redirect(It.IsAny<string>())).Verifiable();
            _contextMock.Setup(c => c.Response).Returns(responseMock.Object);
            _sessionMock.Setup(s => s.Add(BasicSessionFlowViewService.RedirectUrlKey, It.IsAny<string>())).Callback(
                (string name, object value) =>
                _sessionMock.Setup(s => s[BasicSessionFlowViewService.RedirectUrlKey]).Returns(value));
            _sessionMock.Setup(s => s.Add(BasicSessionFlowViewService.RedirectTicketKey, flow)).Verifiable();

            _service.PostRedirectGet(Guid.NewGuid().ToString(), flow, _requestContext);

            _sessionMock.Verify();
            responseMock.Verify();
        }

        [Fact]
        public void PostRedirectGet_NeverIssuesRedirectBack()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Auto, "");
            var responseMock = new Mock<HttpResponseBase>();
            _contextMock.Setup(c => c.Response).Returns(responseMock.Object);
            _sessionMock.Setup(s => s[BasicSessionFlowViewService.RedirectTicketKey]).Returns(flow);

            _service.PostRedirectGet(Guid.NewGuid().ToString(), flow, _requestContext);

            _sessionMock.Verify(s => s.Add(BasicSessionFlowViewService.RedirectUrlKey, It.IsAny<string>()), Times.Never());
            responseMock.Verify();
        }
    }
}